﻿using System;
using System.Collections;
using System.Xml.Xsl;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Text;

namespace Global.Util
{
    /// <summary>
    /// This singleton class should be used to get transformed html 
    /// string from a xsl file.
    /// </summary>
    /// 
    public class XMLSerializer
    {
        public static void SerializeCollectionToFile(object oObject, string sFilename, string sRootElementName)
        {
            try
            {
                XmlSerializer xmlSerializer = new XmlSerializer(oObject.GetType(), new XmlRootAttribute()
                {
                    Namespace = string.Empty,
                    ElementName = sRootElementName
                });
                XmlTextWriter xmlTextWriter = new XmlTextWriter(sFilename, Encoding.Unicode);
                xmlSerializer.Serialize((XmlWriter)xmlTextWriter, oObject);
                xmlTextWriter.Close();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public static void SerializeObjectToFile(object oObject, string sFileName)
        {
            try
            {
                XmlSerializer xmlSerializer = new XmlSerializer(oObject.GetType());
                XmlTextWriter xmlTextWriter = new XmlTextWriter(sFileName, Encoding.UTF8);
                xmlSerializer.Serialize((XmlWriter)xmlTextWriter, oObject);
                xmlTextWriter.Close();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public static string SerializeObjectToString(object oObject)
        {
            try
            {
                XmlSerializer xmlSerializer = new XmlSerializer(oObject.GetType());
                StringWriter stringWriter = new StringWriter();
                xmlSerializer.Serialize((TextWriter)stringWriter, oObject);
                string str = stringWriter.ToString();
                stringWriter.Close();
                return str;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public static object DeserializeCollectionFromFile(Type tOjectType, string sFilename, string sRootElementName)
        {
            object obj = (object)null;
            try
            {
                if (!File.Exists(sFilename))
                    throw new Exception(string.Format("File '{0}' not found.", (object)sFilename));
                XmlSerializer xmlSerializer = new XmlSerializer(tOjectType, new XmlRootAttribute()
                {
                    Namespace = string.Empty,
                    ElementName = sRootElementName
                });
                XmlTextReader xmlTextReader = new XmlTextReader(sFilename);
                if (xmlSerializer.CanDeserialize((XmlReader)xmlTextReader))
                    obj = xmlSerializer.Deserialize((XmlReader)xmlTextReader);
                xmlTextReader.Close();
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return obj;
        }

        public static object DeserializeObjectFromFile(Type tOjectType, string sFileName)
        {
            object obj = null;
            try
            {
                if (!File.Exists(sFileName))
                    throw new IOException(string.Format("File '{0}' not found.", (object)sFileName));
                XmlSerializer xmlSerializer = new XmlSerializer(tOjectType);
                XmlTextReader xmlTextReader = new XmlTextReader(sFileName);
                if (xmlSerializer.CanDeserialize((XmlReader)xmlTextReader))
                    obj = xmlSerializer.Deserialize((XmlReader)xmlTextReader);
                xmlTextReader.Close();
            }
            catch (Exception ex)
            {
            }
            return obj;
        }

        public static object DeserializeCollectionFromFile(string sFilename, string sRootElementName, object objType)
        {
            object obj = (object)null;
            try
            {
                if (!File.Exists(sFilename))
                    throw new IOException(string.Format("File '{0}' not found.", (object)sFilename));
                XmlSerializer xmlSerializer = new XmlSerializer(objType.GetType(), new XmlRootAttribute()
                {
                    Namespace = string.Empty,
                    ElementName = sRootElementName
                });
                XmlTextReader xmlTextReader = new XmlTextReader(sFilename);
                if (xmlSerializer.CanDeserialize((XmlReader)xmlTextReader))
                    obj = xmlSerializer.Deserialize((XmlReader)xmlTextReader);
                xmlTextReader.Close();
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return obj;
        }

        public static object DeserializeObjectFromFile(string sFileName, Type objType)
        {
            object obj = (object)null;
            try
            {
                if (!File.Exists(sFileName))
                    throw new IOException(string.Format("File '{0}' not found.", (object)sFileName));
                XmlSerializer xmlSerializer = new XmlSerializer(objType);
                XmlTextReader xmlTextReader = new XmlTextReader(sFileName);
                if (xmlSerializer.CanDeserialize((XmlReader)xmlTextReader))
                    obj = xmlSerializer.Deserialize((XmlReader)xmlTextReader);
                xmlTextReader.Close();
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return obj;
        }

        public static object DeserializeObjectFromString(Type tOjectType, string objectXmlString)
        {
            object obj = null;
            try
            {
                XmlSerializer xmlSerializer = new XmlSerializer(tOjectType);
                StringReader stringReader = new StringReader(objectXmlString);
                obj = xmlSerializer.Deserialize((TextReader)stringReader);
                stringReader.Close();
            }
            catch (Exception ex)
            {
                throw ex; 
            }
            return obj;
        }
    }
    public class XslTransformer
    {
        #region Variables

        private Hashtable _compiledTransformers;
        private static XslTransformer _instance;
        private static object _lockObj = new object();

        #endregion

        #region Ctor

        private XslTransformer()
        {
            //LoadTransformers();
        }


        #endregion

        #region Properties

        public static XslTransformer Instance
        {
            get
            {
                if (null == _instance)
                {
                    lock (_lockObj)
                    {
                        if (null == _instance)
                        {
                            _instance = new XslTransformer();
                        }
                    }
                }
                return _instance;
            }
        }

        public Hashtable CompiledTransformers
        {
            get 
            { 
                return _compiledTransformers; 
            }
        }

        #endregion

        #region Methods

        private void LoadTransformers()
        {
            _compiledTransformers = new Hashtable();
            try
            {
                string xslFileName = "";
                XslCompiledTransform xslt = null;

                string xslFilePath = AppDomain.CurrentDomain.BaseDirectory + "XSLT";
                DirectoryInfo dirInfo = new DirectoryInfo(xslFilePath);
                FileInfo[] infoList = dirInfo.GetFiles();
                for (int i = 0; i < infoList.Length; i++)
                {
                    if (infoList[i].Extension.Equals(".xsl") ||
                        infoList[i].Extension.Equals(".xslt"))
                    {
                        xslFileName = xslFilePath + @"\" + infoList[i].Name;
                        xslt = new XslCompiledTransform();
                        xslt.Load(xslFileName);
                        CompiledTransformers.Add(infoList[i].Name, xslt);
                    }
                }
            }
            catch (Exception e)
            {
                throw e;
            }
        }


        public string TransformToHtml(object obj, string xslFileName)
        {
            XmlWriter xmlWriter = null;
            XmlReader reader = null;
            TextReader textReader = null;
            try
            {
                string xslFileNameWithPath = AppDomain.CurrentDomain.BaseDirectory + @"XSLT\" + xslFileName;
                if (!File.Exists(xslFileNameWithPath))
                {
                    throw new ApplicationException(string.Format("{0} is not available", xslFileNameWithPath));
                }
                XslCompiledTransform xslt = new XslCompiledTransform();
                xslt.Load(xslFileNameWithPath);

                
                //Uncomment if data is required to save
                //string xmlFileName = @"E:\Temp2\" + obj.GetType().Name + ".xml";
                string xmlFileName = @"D:\Temp\" + "serialized" + ".xml";

                if (File.Exists(xmlFileName))
                {
                    File.Delete(xmlFileName);
                }
                XMLSerializer.SerializeObjectToFile(obj, xmlFileName);
                string outputFile = @"D:\Temp\" + "serialized" + ".html";
                if (File.Exists(outputFile))
                {
                    File.Delete(outputFile);
                }
                xslt.Transform(xmlFileName, outputFile);
                 
                
                // getting the XmlReader
                XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType());

                Stream str = new MemoryStream();
                xmlWriter = new XmlTextWriter(str, Encoding.UTF8);
                xmlSerializer.Serialize(xmlWriter, obj);
                str.Position = 0;
                reader = new XmlTextReader(str);

                Stream writeStream = new MemoryStream();
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Indent = true;
                settings.IndentChars = "\t";

                XmlWriter writer = new XmlTextWriter(writeStream, Encoding.UTF8);
                //writer.Settings.CheckCharacters = false;

                xslt.Transform(reader, writer);

                writeStream.Position = 0;
                textReader = new StreamReader(writeStream);
                string result = textReader.ReadToEnd();

                result = result.Replace("<?xml version=\"1.0\" encoding=\"utf-8\"?>", "");
                return result;
            }
            catch (Exception e)
            {
                throw e;
            }
            finally
            {
                //Closing the readers and streams
                if (null != xmlWriter)
                {
                    xmlWriter.Close();
                }
                if (null != reader)
                {
                    reader.Close();
                }
                if (null != textReader)
                {
                    textReader.Close();
                }
            }
        }


        public string TransformToHtml(string xmlString, string xslFileName)
        {
            XmlWriter xmlWriter = null;
            XmlReader reader = null;
            TextReader textReader = null;
            StreamReader strReader = null;
            MemoryStream ms = null;
            try
            {
                // getting the transformer
                string xslFileNameWithPath = AppDomain.CurrentDomain.BaseDirectory + @"Xslts\" + xslFileName;
                if (!File.Exists(xslFileNameWithPath))
                {
                    throw new ApplicationException(string.Format("{0} is not available", xslFileNameWithPath));
                }
                XslCompiledTransform xslt = new XslCompiledTransform();
                xslt.Load(xslFileNameWithPath);

                // getting the XmlReader
                ms = new MemoryStream(GetStringToByte(xmlString));
                strReader = new StreamReader(ms, Encoding.UTF8);
                reader = new XmlTextReader(strReader);

                Stream writeStream = new MemoryStream();
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Indent = true;
                settings.IndentChars = "\t";

                XmlWriter writer = new XmlTextWriter(writeStream, Encoding.UTF8);
                //writer.Settings.CheckCharacters = false;

                xslt.Transform(reader, writer);

                writeStream.Position = 0;
                textReader = new StreamReader(writeStream);
                string result = textReader.ReadToEnd();

                result = result.Replace("<?xml version=\"1.0\" encoding=\"utf-8\"?>", "");
                return result;
            }
            catch (Exception e)
            {
                throw e;
            }
            finally
            {
                //Closing the readers and streams
                if (null != xmlWriter)
                {
                    xmlWriter.Close();
                }
                if (null != reader)
                {
                    reader.Close();
                }
                if (null != textReader)
                {
                    textReader.Close();
                }
                if (null != ms)
                {
                    ms.Close();
                }
                if (null != strReader)
                {
                    strReader.Close();
                }
            }
        }

        private static byte[] GetStringToByte(string inputString)
        {
            UTF8Encoding encoding = new UTF8Encoding();

            return encoding.GetBytes(inputString);
        }


        #endregion
    }
}
